package classes.classloader;

import java.util.HashMap;
import java.util.Map;

public class ClassModifier {
    private final static int CONSTANT_INDEX = 8;
    private final static int U1 = 1;
    private final static int U2 = 2;

    private final static Map<Integer, ConstantType> constant_type_map = new HashMap<>(18);

    static {
        constant_type_map.put(1, new ConstantType(-1, "Utf8_info"));
        constant_type_map.put(3, new ConstantType(5, "Integer_info"));
        constant_type_map.put(4, new ConstantType(5, "Float_info"));
        constant_type_map.put(5, new ConstantType(9, "Long_info"));
        constant_type_map.put(6, new ConstantType(9, "Double_info"));
        constant_type_map.put(7, new ConstantType(3, "Class_info"));
        constant_type_map.put(8, new ConstantType(3, "String_info"));
        constant_type_map.put(9, new ConstantType(5, "FieldRef_info"));
        constant_type_map.put(10, new ConstantType(5, "MethodRef_info"));
        constant_type_map.put(11, new ConstantType(5, "InterfaceMethodRef_info"));
        constant_type_map.put(12, new ConstantType(5, "NameAndType_info"));
        constant_type_map.put(15, new ConstantType(4, "MethodHandle_info"));
        constant_type_map.put(16, new ConstantType(3, "MethodType_info"));
        constant_type_map.put(18, new ConstantType(5, "InvokeDynamic_info"));
    }

    /**
     * 替换字节中的字符串
     * @param bytes
     * @param oldStr
     * @param newStr
     */
    public static byte[] replaceUtf8(byte[] bytes, String oldStr, String newStr) {
        if(oldStr == null || newStr == null)
            throw new IllegalArgumentException("str is null");
        int offset = CONSTANT_INDEX;
        int constSize = ByteUtil.u2(bytes[offset ++], bytes[offset ++]);
        System.out.println("常量池大小 -> " + constSize);
        for (int i = 1; i < constSize; i++) {
            int tag = ByteUtil.u1(bytes[offset ++]);
            ConstantType constantType = constant_type_map.get(tag);
            if(constantType == null)
                throw new RuntimeException("constant type not found, tag: " + tag);
            System.out.printf("#%-4d -> %s, tag -> %d\n", i, constantType, tag);
            // utf-8
            if(tag == 1) {
                System.out.println("\t\tUtf8_info");
                int utf8Length = ByteUtil.u2(bytes[offset ++], bytes[offset ++]);
                String s = ByteUtil.bytes2Str(bytes, offset, utf8Length);
                // 如果匹配， 替换为新的字符串
                if(s.equals(oldStr)) {
                    // 替换为新字符串
                    bytes = ByteUtil.replaceBytes(bytes, offset, oldStr.length(), newStr.getBytes());
                    // 如果两个字符串的长度不一样
                    if(newStr.length() != oldStr.length()) {
                        utf8Length = newStr.length();
                        // 写入新的长度
                        bytes = ByteUtil.replaceBytes(bytes, offset - U2, U2, ByteUtil.int2Byte2(utf8Length));
                    }
                    s = newStr;
                }
                System.out.printf("\t\tSize[%d] - %s\n", utf8Length, s);
                offset += utf8Length;
            } else {
                if(constantType.length < 0)
                    throw new RuntimeException("constant length less then 0, constant type: " + constantType);
                offset += constantType.length - 1;
            }
        }
        return bytes;
    }

    private static class ConstantType {
        private int length;
        private String name;

        public ConstantType(int length, String name) {
            this.length = length;
            this.name = name;
        }

        @Override
        public String toString() {
            return "ConstantType{length=" + length +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
}
